package com.lvxtech.gateway.common.filter.factory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.handler.FilteringWebHandler;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.cors.reactive.CorsWebFilter;

import com.lvxtech.gateway.common.filter.GlobalRequestIdFilter;

import reactor.core.publisher.Mono;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

import java.util.Arrays;
import java.util.List;

/**
 * Email miles02@163.com
 *
 * @author fangzhipeng
 * create 2018-11-16
 **/
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenGatewayFilterFactory.Config> {


	private static final Log log = LogFactory.getLog(TokenGatewayFilterFactory.class);
	private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
	private static final List<String> FIELDS = Arrays.asList("type");
	
	private static final List<RequestLogType> AllSLogType = Arrays.asList(RequestLogType.ALL);

	@Override
	public List<String> shortcutFieldOrder() {
		return FIELDS;
	}

	public TokenGatewayFilterFactory() {
		super(Config.class);
	}

	@Override
	public GatewayFilter apply(Config config) {
		return (exchange, chain) -> {
			exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
			String requestId = exchange.getAttribute(GlobalRequestIdFilter.REQUEST_ID);
			if (requestId != null) {
				MDC.put(GlobalRequestIdFilter.REQUEST_ID, requestId);
			}
			return chain.filter(exchange).then(
					Mono.fromRunnable(() -> {
						String requestId2 = exchange.getAttribute(GlobalRequestIdFilter.REQUEST_ID);
						if (requestId2 != null) {
							MDC.put(GlobalRequestIdFilter.REQUEST_ID, requestId2);
						}
						StringBuilder builder = new StringBuilder("\n---> Request ")
								.append(exchange.getRequest().getMethod()).append(" ")
								.append(exchange.getRequest().getURI())
								.append(" -> ").append(exchange.getRequest().getRemoteAddress());
//								.append("\n---> Request-Param: ").append(exchange.getRequest().getQueryParams());
//						if(AllSLogType.contains(config.getType())){
//							//Content-Type=[application/json], User-Agent=[PostmanRuntime/7.26.5], Accept=[*/*], Cache-Control=[no-cache], Postman-Token=[22e55beb-c5e6-4ba6-ab1f-5d8a35d0d820], Host=[localhost:1000], Accept-Encoding=[gzip, deflate, br], Connection=[keep-alive], Content-Length=[20]}
////							List<String> contentTypes = exchange.getRequest().getHeaders().get("Content-Type");
////							if(contentTypes!=null&&contentTypes.contains("application/json")){
//////								List<String> contentLengths = exchange.getRequest().getHeaders().get("Content-Length");
//////								exchange.getRequest().getBody().;
////							}
//						}
						if(RequestLogType.ALL.equals(config.getType())){
							builder.append("\n---> Request-Header: ").append(exchange.getRequest().getHeaders());
						}
						Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
						if (startTime != null) {
							builder.append("\n<--- Response : ").append(exchange.getResponse().getStatusCode()).append(" (")
								.append((System.currentTimeMillis() - startTime)).append("ms)");
						}
//						if(AllSLogType.contains(config.getType())){
//							builder.append("\n---> Response-Body: ").append(exchange.getResponse());
//						}
						if(RequestLogType.ALL.equals(config.getType())){
							builder.append("\n<--- Response-Header: ").append(exchange.getResponse().getHeaders());
						}
						builder.append("\n<--> ").append(exchange.getAttributes().get(GATEWAY_ROUTE_ATTR));
						log.info(builder.toString());
					})
			);
		};
	}



	public enum RequestLogType{
		
		ALL,
		
		;
	}


	public static class Config {

		private RequestLogType type;

		public RequestLogType getType() {
			return type;
		}

		public void setType(RequestLogType type) {
			this.type = type;
		}
		
		
	}
}
